[Ruby on Rails] dm-redis-adapterでRedisのデータをModelのように扱う
はじめに
Ruby on RailsにてRedisに登録するデータを扱う際に、通常のActiveRecordのModelのようにデータを操作できる dm-redis-adapter を紹介したいと思います。これを使うと、Redisに登録するデータを、以下のように扱うことができます。
- 一つのModelを一レコードのように扱い、複数のプロパティを持たせて登録する
- 登録するデータにidを持たせ、自動的にインクリメントした値を登録する
- モデル名.create のように、ActiveRecordと同じようなメソッドを使用してデータを操作する
以下に、Gemの使用方法やソースの例を記述します。
Gemの使用準備
dm-redis-adapterをRuby on Railsで扱う方法についてです。データの登録先としてRedisを使うので、予めインストールしておいてください。(もしくはサーバなどに用意しておく)
1.Gemのインストール
Gemfileに以下を記述し、$ bundle install します。
gem 'redis-objects' gem 'dm-core' gem 'dm-redis-adapter'
2.接続情報とRedisオブジェクトの作成
/config/initializersフォルダ内に、Redisの接続情報とオブジェクトを作成するためのソースを作成します。今回は「redis.rb」というファイルを作成し、以下のように記述しました。
/config/initializers/redis.rb
Redis.current = Redis.new(:host => '127.0.0.1', :port => 6379)
上記例は、ローカルでRedisを実行する場合のものです。(確認はしてませんが)サーバなど別マシン上でRedisを実行する場合は、「:host」にそのマシンのIPを指定してください。
Modelの定義
Redisの登録するデータについて、Modelを定義します。今回はUserモデルを作成し
- idを保持し、idにて検索できるようにする
- 項目として「name」「email」を持つようにする
ようにしました。以下、Userモデルのソースです。
/app/models/user.rb
DataMapper.setup(:default, {:adapter => "redis"}) class User include Redis::Objects include DataMapper::Resource property :id, Serial value :name value :email end User.finalize
一番上、一番下の行は「お約束」のようなものです(笑)。重要なのは3〜11行目(つまりUserクラス)で
- UserクラスはActiveRecordを継承せず、Redis::Object、DataMapper::Resourceをincludeする
- 7行目でidをプロパティとして定義し、AutoIncrementさせるため「Serial」で定義する
- 保持したい項目(今回はname、email)を「value」として定義する
を行っています。
Redisへの登録・参照・更新・削除
上記のUserモデルを使用して、データを操作します。今回はRspecにて記述しました。RSpecを実行する前に、以下のコマンドでRedisを起動します。
$ radis-server
/spec/models/user_spec.rb
require 'rails_helper' RSpec.describe User, :type => :model do include Redis::Objects before do Redis.current.flushall end after do Redis.current.flushall end describe 'User Data' do before do user = User.create user.name = 'TestUser' user.email = 'test@ggg.com' @id1 = user.id user = User.create user.name = 'TogoJuzo' user.email = 'duke@ggg.com' @id2 = user.id end it 'should find.' do user = User.first(id: @id1) name = user.name.value email = user.email.value expect(name).to eq('TestUser') expect(email).to eq('test@ggg.com') user = User.first(id: @id2) name = user.name.value email = user.email.value expect(name).to eq('TogoJuzo') expect(email).to eq('duke@ggg.com') end it 'should update.' do user = User.first(id: @id2) user.email = 'm16@ggg.com' updated = User.first(id: @id2) email = updated.email.value expect(email).to eq('m16@ggg.com') end it 'should delete.' do user = User.first(id: @id1) user.destroy user = User.first(id: @id1) expect(user).to be_nil end end end
データの登録
15〜25行目のbeforeの中で、Userモデルを登録しています。このbeforeを実行すると、Redisには以下のようにデータが登録されます。
$ redis-cli 127.0.0.1:6379> keys * 1) "user:1:email" 2) "user:2:name" 3) "users:id:all" 4) "user:1:name" 5) "user:2:email" 6) "users:id:serial"
Redisのキーとして「user:idの値:項目名」が登録され、それぞれが別レコードとして保持されていることが分かります。登録されている値を確認してみると、以下のようになります。
127.0.0.1:6379> get user:1:email "test@ggg.com" 127.0.0.1:6379> get user:1:name "TestUser"
この「user:idの値:項目名」をキーとして登録していることで、dm-redis-adapterがRedisに登録するデータをModelのように扱うことを実現しているようです。
データの参照
27〜41行目で、データの参照を行っています。firstメソッドの引数に、対象のidを指定することで、ActiveRecordのModelに近い形で参照しています。
データの更新
43〜50行目で、データの更新を行っています。注意すべき点は、項目の値を書き換えた後(45行目)、updateなどの更新のためのメソッドを呼び出していないことです。
データの削除
52〜58行目で、データの削除を行っています。こちらもdestroyメソッドを使用し、ActiveRecordのModelに近い形で実現しています。注意すべき点は、destoryしたデータはfirstでは取得出来ないが、Redis上では物理的には削除されていないことです(redis-cli上で確認すると、データが存在する)。Redis内のキー「users:id:all」「users:id:serial」を使用して、dm-redis-adapterが削除扱いとしていると思われるのですが、現時点では未確認です。
まとめ
dm-redis-adapterを使い、key-valueの組み合わせであるRedis上のデータをModelに近い形で扱うことができました。